MVC 和命名空间
要确保应用中的视图、状态和数据彼此清晰分离,才能让架构更加整洁有序且更加健壮。模型应当从视图和控制器中解耦出来。与数据操作和行为相关的逻辑都应当放入模型中,通过命名空间
进行管理。
在JavaScript 中,通过给对象添加属性来管理一个命名空间,这个命名空间可以是函数,也可以是变量,比如:
var User = {
records: [ /* ... */ ]
};
User
的数组数据就在命名空间User.records
中。和user 相关的函数也可以放入User 模型的命名空间里。比如用fetchRemote()
函数来从服务器端获取user 的数据:
var User = {
records: [],
fetchRemote: function(){ /* ... */ }
};
将模型的属性保存至命名空间中的做法可以确保不会产生冲突,这也是符合MVC 原则的,同时也能避免代码变成一堆函数和回调混杂在一起的大杂烩。
可以对命名空间做一点改进,将那些在真实user 对象上的和user 实例相关的函数也都添加进去。假设user 记录包含一个destory()
函数,它是和具体的user 相关的,因此这个函数应当基于User 实例进行调用:
var user = new User;
user.destroy()
为了做到这一点,应当将User 写成一个类,而不是一个简单对象:
var User = function(atts){
his.attributes = atts || {};
};
User.prototype.destroy = function(){
/* ... */
};
对于那些和具体的user 不相关的函数和变量,则可以直接定义在User 对象中:
User.fetchRemote = function(){
/* ... */
};
构建对象关系映射(ORM)
对象关系映射(Ojbect-relational mapper,简称ORM)是在除JavaScript 以外的编程语言中常见的一种数据结构。在JavaScript 应用中,对象关系映射也是一种非常有用的技术,它可以用来做数据管理及用做模型。比如使用ORM 可以将模型和远程服务捆绑在一起,任何模型实例的改变都会在后台发起一个Ajax 请求到服务器端。或者将模型实例和HTML 元素绑定在一起,任何对实例的更改都会在界面中反映出来。
现在让来创建一个自定义ORM。
本质上讲,ORM 是一个包装了一些数据的对象层。以往ORM 常用于抽象SQL 数据库,但在这里ORM 只是用于抽象JavaScript 数据类型。这个额外的层有一个好处,可以通过给它添加自定义的函数和属性来增强基础数据的功能。比如添加数据的合法性验证、监听、数据持久化及服务器端的回调处理等,这样会增加代码的重用率。
原型继承
这里使用Object.create()
来构造ORM,这里使用基于原型(prototype-based)的继承,而没有用到构造函数和new关键字。
Object.create()
只有一个参数即原型对象,它返回一个新对象,这个新对象的原型就是传入的参数。换句话说,传入一个对象,返回一个继承了这个对象的新对象。
对于不支持的Object.create()
的浏览器 ,可以很容易地模拟出这个函数:
if (typeof Object.create !== "function")
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
现在来创建Model 对象,Model 对象将用于创建新模型和实例:
var Model = {
inherited: function(){},
created: function(){},
prototype: {
init: function(){}
},
create: function(){
var object = Object.create(this);
object.parent = this;
object.prototype = object.fn = Object.create(this.prototype);
object.created();
this.inherited(object);
return object;
},
init: function(){
var instance = Object.create(this.prototype);
instance.parent = this;
instance.init.apply(instance, arguments);
return instance;
}
};
create() 函数返回一个新对象,这个对象继承自Model 对象,使用它来创建新模型。
init() 函数返回一个新对象,它继承自Model.prototype——如Model 对象的一个实例:
var Asset = Model.create();
var User = Model.create();
var user = User.init();
添加ORM 属性
现在如果给Model 对象添加属性,对于继承的模型来说,这些新增属性都是可访问的:
// 添加对象属性
jQuery.extend(Model, {
find: function(){}
});
// 添加实例属性
jQuery.extend(Model.prototype, {
init: function(atts) {
if (atts) this.load(atts);
},
load: function(attributes){
for(var name in attributes)
this[name] = attributes[name];
}
});
jQuery.extend() 只是代替for 循环手动复制属性的一种快捷方式,这和在load()
函数中的做法差不多。现在,对象和实例属性都传播到了单独的模型里:
assertEqual( typeof Asset.find, "function" );
实际上我们会增加很多属性,因此还需将extend() 和include() 添加至Model 对象中:
var Model = {
/* ……代码片段……*/
extend: function(o){
var extended = o.extended;
jQuery.extend(this, o);
if (extended) extended(this);
},
include: function(o){
var included = o.included;
jQuery.extend(this.prototype, o);
if (included) included(this);
}
};
// 添加对象属性
Model.extend({
find: function(){}
});
// 添加实例属性
Model.include({
init: function(atts) { /* ... */ },
load: function(attributes){ /* ... */ }
});
现在可以创建新的资源并设置一些属性:
var asset = Asset.init({name: "foo.png"});
【公开记录学习JS MVC,不知道能坚持多久= =。以《基于MVC的JavaScript web富应用开发》为主要学习资料。】
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。